import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JLabel;

@SuppressWarnings("serial")
public class GameClient extends JFrame implements MouseListener{
	public GameClient() {} // Constructor
	private BufferedReader in;
	private PrintWriter out;
	private JFrame frame;
	private int GameSizeX, GameSizeY;
	private static GameClient data;
	private JPanel textPanel, gamePanel, statusPanel;
	private JLabel Player1Name, Player2Name, serverStatus, Player1Score, Player2Score;
	private int lastX = 0, lastY = 0;
	private JRadioButton[][] positions;
	private Boolean Turn = false;

	/** Creates all object in the game window<p>
	 *
	 * @param x received argument from function GameGUI
	 * @param y received argument from function GameGUI
	 * @return A JPanel containing all components
	 * @see GameGUI
	 */
	private JPanel createContentPane(int x, int y) {
		this.GameSizeX = x+1;
		this.GameSizeY = y+3;

		// We create a bottom JPanel to place everything on.
		JPanel GUI = new JPanel();
		GUI.setLayout(null);

		// Creation of a Panel to contain the JLabels
		textPanel = new JPanel();
		textPanel.setLayout(null);
		textPanel.setLocation(10, 5);
		textPanel.setSize(360, 90);
		GUI.add(textPanel);

		//Create the Game panel for the Radio buttons
		gamePanel = new JPanel();
		gamePanel.setLayout(null);
		gamePanel.setLocation(10, 110);
		gamePanel.setSize(380, 580);
		GUI.add(gamePanel);


		// Status label
		statusPanel = new JPanel();
		statusPanel.setLayout(null);
		statusPanel.setLocation(10, 690);
		statusPanel.setSize(360, 30);
		GUI.add(statusPanel);

		positions = new JRadioButton[GameSizeX][GameSizeY]; //Get the grid size to actual size
		for (int row = 0; row < (GameSizeY); row++)
			for (int col = 0; col < (GameSizeX); col++) {
				positions[col][row] = new JRadioButton();
				positions[col][row].setBounds(col*(400 / (x+1)), row*(580/(y+3)), 17, 17);
				positions[col][row].setEnabled(false);
				positions[col][row].addMouseListener(new PressedMouseListenser(col, row));

				if((col == x/2) && (row == y/2+1)){ //Marks the center and set the (last known) location
					positions[col][row].setSelected(true);
					this.lastX = x/2;
					this.lastY = y/2+1;
				}

				if(row==0 || row == y+2){ // Hide the top and bottom to present only 3 in the middle (goal)
					int length = ((x+1)/2-1);
					if(col<=length-1)
						positions[col][row].setVisible(false);
					else if(col>=length+3)
						positions[col][row].setVisible(false);
				}
				gamePanel.add(positions[col][row]);

			}
		serverStatus = new JLabel("Status:");
		serverStatus.setBounds(10, 0, 300, 14);
		statusPanel.add(serverStatus);

		JLabel lblPlayer = new JLabel("You");
		lblPlayer.setBounds(10, 22, 55, 14);
		textPanel.add(lblPlayer);

		JLabel lblPlayer_1 = new JLabel("Opponent");
		lblPlayer_1.setBounds(304, 22, 55, 14);
		textPanel.add(lblPlayer_1);

		JLabel lblPlayerScore = new JLabel("Score:");
		lblPlayerScore.setBounds(10, 70, 55, 14);
		textPanel.add(lblPlayerScore);

		JLabel lblPlayer_1Score = new JLabel("Score:");
		lblPlayer_1Score.setBounds(304, 70, 55, 14);
		textPanel.add(lblPlayer_1Score);

		Player1Score = new JLabel("0");
		Player1Score.setBounds(50, 70, 20, 14);
		textPanel.add(Player1Score);

		Player2Score = new JLabel("0");
		Player2Score.setBounds(344, 70, 20, 14);
		textPanel.add(Player2Score);

		Player1Name = new JLabel("(name)");
		Player1Name.setBounds(10, 54, 60, 14);
		textPanel.add(Player1Name);

		Player2Name = new JLabel("(name)");
		Player2Name.setBounds(304, 54, 60, 14);
		textPanel.add(Player2Name);

		//Image : VS
		BufferedImage myPicture;
		try {
			myPicture = ImageIO.read(new File(System.getProperty("user.dir") + "\\index.jpg"));
			JLabel VS = new JLabel(new ImageIcon(myPicture));
			VS.setLocation(140, 0);
			VS.setSize(90, 90);
			textPanel.add(VS);

		} catch (IOException e) {
			e.printStackTrace();
		}

		return GUI;
	}

	public static void main(String[] arg)
	{
		try {
			GameGUI(false, null, null); // hidden, player, socket
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	/** Communication received from server
	 * @param serverData receiving data/command from server by ServerListener
	 * @throws IOException
	 * @throws InterruptedException
	 * @see ServerListener
	 */
	static void TalkToServer(String serverData) throws IOException, InterruptedException {

		if(serverData.startsWith("draw")){
			String rcv = serverData;
			String split[] = rcv.split(",");

			Graphics g = data.gamePanel.getGraphics();
			g.setColor(Color.red);

			data.positions[Integer.parseInt(split[1])][Integer.parseInt(split[2])].setSelected(false); // Show current position
			data.positions[Integer.parseInt(split[3])][Integer.parseInt(split[4])].setSelected(true); // unSelect last position
			data.lastX = Integer.parseInt(split[3]); // Update "last position"
			data.lastY = Integer.parseInt(split[4]);

			g.drawLine(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8]));
		}

		else if(serverData.startsWith("highscore"))
		{
			String rcv = serverData;
			String splitScore[] = rcv.split(",");
			int numberOfScore = splitScore.length;

			String presentScore = "";
			int distance = 0;
			for(int i = 1; i < numberOfScore; i+=3)
			{
				distance = 20 - splitScore[i].length();
				presentScore = presentScore + String.format("%-" + distance + "s %-10s %5s \n", splitScore[i], splitScore[i+1], splitScore[i+2]);
			}

			int n = JOptionPane.showConfirmDialog(null, presentScore, "Highscore", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE);
			if (n == JOptionPane.YES_OPTION) {
				System.out.println("Done");
				data.frame.dispose(); // Dispose our Game window
				System.exit(0);	// Exit application successfully 
			} else {
				System.out.println("Quit");
				data.frame.dispose(); // Dispose our Game window
				System.exit(0);	// Exit application successfully 
			}
		}

		else if(serverData.startsWith("retValid"))
		{
			String rcv = serverData;
			String split[] = rcv.split(",");

			Graphics g = data.gamePanel.getGraphics();
			g.setColor(Color.blue);

			data.positions[Integer.parseInt(split[1])][Integer.parseInt(split[2])].setSelected(false); // Show current position
			data.positions[Integer.parseInt(split[3])][Integer.parseInt(split[4])].setSelected(true); // unSelect last position
			data.lastX = Integer.parseInt(split[3]); // Update "last position"
			data.lastY = Integer.parseInt(split[4]);

			g.drawLine(Integer.parseInt(split[5]), Integer.parseInt(split[6]), Integer.parseInt(split[7]), Integer.parseInt(split[8]));
			data.Turn = false; // disable the client to send more by mousePressed()
		}

		else if(serverData.startsWith("Status"))
			data.serverStatus.setText(serverData);

		else if(serverData.startsWith("Turn"))
			data.Turn = true; // Set the Client to be able to send by mousePressed()

		else if(serverData.startsWith("Score")){
			String rcv = serverData;
			String split[] = rcv.split(",");
			if(data.Player1Name.getText().equals(split[1])){
				System.out.println("Player (" + data.Player1Name.getText() + ") score!");
				String prevScore = data.Player1Score.getText();
				int newScore = Integer.parseInt(prevScore) +1;
				data.Player1Score.setText(Integer.toString(newScore));
			}
			else {
				System.out.println("Player (" + data.Player2Name.getText() + ") score!");
				String prevScore = data.Player2Score.getText();
				int newScore = Integer.parseInt(prevScore) +1;
				data.Player2Score.setText(Integer.toString(newScore));
			}
		}

		else
			System.out.println("What shall i do with: " + serverData);

	}

	/** Call the creation of GUI and open connectGUI, get and set the first stage of data exchange with server
	 * @param state true if main window should be visible, false will open up ConnectGUI
	 * @param player1 name of the player from ConnectGUI
	 * @param socket connection between client and server
	 * @throws IOException required by streams and readLine()
	 * @see ConnectGUI
	 */
	static void GameGUI(boolean state, String player1, Socket socket) throws IOException {

		if(state){ //if state is true, the user has pressed 'connect to server'
			data = new GameClient();
			data.frame = new JFrame("Paper-Soccer");

			//data.socket = socket; // Set the socket to be private and accessible thought whole GameClient
			data.in = new BufferedReader(new InputStreamReader(socket.getInputStream())); //BufferedReader is accessible
			data.out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); //PrintWriter is accessible

			// Get the game plan size
			String size = data.in.readLine();
			String[] size_split = size.split(",");
			System.out.println("My size is splitted to " + size_split[0] + " " + size_split[1]);

			// Print out window
			data.frame.setResizable(false);
			data.frame.setSize(400, 750);
			data.frame.setContentPane(data.createContentPane(Integer.parseInt(size_split[0]), Integer.parseInt(size_split[1]))); // Send the size of our Game plan.
			data.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			data.frame.setVisible(true); 

			// Send the player name
			System.out.println("My playername is set to : " + player1);
			data.out.println(player1);
			data.Player2Name.setText(data.in.readLine());

			// Receive status text
			data.serverStatus.setText(data.in.readLine()); 

			// Start the ServerListener
			ServerListener SL = new ServerListener(data.in, true);
			SL.start();
		}
		else { // This get called at start to present the connecting GUI
			System.out.println("The MainGUI is hidden");
			ConnectGUI.main(null); // Show ConnectGUI
		}

		// Just a check
		if(player1 != null)
			data.Player1Name.setText(player1);
	}

	/* This function is called every time a RadioButton is pressed in our Window*/
	private class PressedMouseListenser extends MouseAdapter {
		private int x, y;

		public PressedMouseListenser(int col, int row) { // Get the coordinates from an mousePressed of our RadioButtons.
			this.x = col;
			this.y = row;
		}
		/* Send requested position for validation to server */
		@Override
		public void mousePressed(MouseEvent e) {


			/*
			 * Check to see that the next move is in valid length of last move + draw the lines and select last visited node.
			 */

			if(data.Turn){ // See if client is verified to make an move
				if((x+1 >= lastX && x-1 <= lastX) && (y+1 >= lastY && y-1 <= lastY) && !(x == lastX && y == lastY) 
						|| ((lastX >= 4 && lastX <= 6) && (lastY == 1 || lastY == 11) && (y == 0 || y == 12))) // Valid move (length from last draw)
				{
					int fromX = 0, fromY = 0;
					// Correct some draw problems
					if(x < lastX)
						fromX = e.getComponent().getX() + 1*(400 / (GameSizeX+1));
					else if(x == lastX)
						fromX = e.getComponent().getX();
					else
						fromX = e.getComponent().getX() - 1*(400 / (GameSizeX+1));
					if(y < lastY)
						fromY = e.getComponent().getY() + 1*(580 / (GameSizeY+3));
					else if(y == lastY)
						fromY = e.getComponent().getY();
					else
						fromY = e.getComponent().getY() - 1*(580 / (GameSizeY+3));

					// Some temp variables
					int tmpX1, tmpX2, tmpY1, tmpY2;
					tmpX1 = e.getComponent().getX()+9;
					tmpY1 =  e.getComponent().getY()+9;
					tmpX2 = fromX+9;
					tmpY2 = fromY+9;

					//Send validate request
					data.out.println("validate," + data.Player1Name.getText() + "," + lastX + "," + lastY + "," + x + "," + y +  "," + tmpX1 +","+ tmpY1 + "," + tmpX2 +","+ tmpY2);
				}

			}
			else
				// If it is not our turn we do wait
				System.out.println("We need to await move from other client!");
		}

	}
	
	@Override
	public void mouseClicked(MouseEvent arg0) {
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {	
	}

	@Override
	public void mousePressed(MouseEvent e) {	
	}
}
